/*
 * jsiomodel.cpp
 *
 *  Created on: 2009-6-29
 *      Author: root
 */
#include "stdafx.h"
#include"jsiomodel.h"
#include"jssocket.h"
CJSIOModel::CJSIOModel()
{
	int i;
	for (i = 0; i < JSMAXPOOLSIZE; i++)
	{
		pool[i].fd = -1;
		pool[i].event = -1;
		pool[i].eventCallBack = NULL;
	}
	m_maxPoolIndex = -1;
    m_maxFd=-1;

    FD_ZERO(&m_rdSet);
	FD_ZERO(&m_wrSet);
	FD_ZERO(&m_exSet);

	pthread_mutex_init(&m_mutex, NULL);
	pthread_attr_t attr;

	pthread_attr_init(&attr);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	pthread_create(&m_workThread, NULL, Work, this);
}

CJSIOModel::~CJSIOModel()
{
	pthread_mutex_destroy(&m_mutex);
}

int CJSIOModel::AddNewFd(int fd, int event, EventCallBack eventCallBack)
{
	int i;
	int rt = -1;

	for (i = 0; i < JSMAXPOOLSIZE; i++)
	{
		if (pool[i].fd == -1)
		{
			pool[i].fd = fd;
			pool[i].event = event;
			pool[i].eventCallBack = eventCallBack;

			rt = i;
			if (m_maxPoolIndex < i)
			{
				m_maxPoolIndex = i;
			}
			if (JSISSETMASK(JSREADMASK,event))
			{
				FD_SET(fd, &m_rdSet);
			}
			if (JSISSETMASK(JSWRITEMASK,event))
			{
				FD_SET(fd, &m_wrSet);
			}
			if (JSISSETMASK(JSEXCEPTIONMASK,event))
			{
				FD_SET(fd, &m_exSet);
			}
			if(m_maxFd<fd)
			{
				m_maxFd=fd;
			}
			break;
		}
	}
	
	if (rt == -1)
	{
		perror("add Fd");
	}

	return rt;
}

int CJSIOModel::ClearFd(int fd)
{
//	printf("clear fd=%d\n", fd);
	int i;
	int rt = -1;

	for (i = 0; i < m_maxPoolIndex + 1; i++)
	{
		if (fd == pool[i].fd)
		{
			pool[i].fd = -1;
			pool[i].event = -1;
			pool[i].eventCallBack = NULL;
			rt = i;
			FD_CLR(fd,&m_rdSet);
			FD_CLR(fd,&m_wrSet);
			FD_CLR(fd,&m_exSet);
            
			close(fd);
			if (i == m_maxPoolIndex)
			{
				for (--i; i >= 0 && pool[i].fd < 0; i--)
				{
					;
				}
				m_maxPoolIndex = i;
			}
			if (m_maxFd==fd)
			{
				m_maxFd=0;
				for(int j=0;j<m_maxPoolIndex+1;j++)
				{
					if(pool[i].fd>m_maxFd)
						m_maxFd=pool[i].fd;
				}
			}
		}
	}

	if (rt == -1)
	{
		perror("clear Fd");
	}
//	printf("clear over\n");
	return rt;
}

void* CJSIOModel::Work(void*arg)
{
	CJSIOModel *pThis = (CJSIOModel*) arg;
	fd_set wrSet;
	fd_set rdSet;
	fd_set exSet;

	int maxFd;
	int rt = -1;

	while (1)
	{
		timeval tv;
		tv.tv_sec = 0;
		tv.tv_usec = 100;

		//printf("Work... m_maxPoolIndex=%d\n", pThis->m_maxPoolIndex);

		rdSet=pThis->m_rdSet;
		wrSet=pThis->m_wrSet;	
		exSet=pThis->m_exSet;

		bool bShouldSleep = true;

//		for (int i = 0; i < JSMAXPOOLSIZE; i++)
//
//			printf("pool[%d]=%d  ",i, pThis->pool[i].fd);
//		printf("\n");


		int n = select(pThis->m_maxFd + 1, &rdSet, &wrSet, &exSet, &tv);
		if (n == 0)
		{
			//bShouldSleep = false;
			//printf("Work...n=0\n");
			continue;
		}

		for (int i = 0; i < pThis->m_maxPoolIndex + 1; i++)
		{
			if ((pThis->pool[i]).fd == -1)
			{
				continue;
			}
            int fd = pThis->pool[i].fd;

			EventCallBack handler=pThis->pool[i].eventCallBack;
			
			if (FD_ISSET(fd, &rdSet))
			{
				bShouldSleep = false;
				(*handler)(fd,JSREADEVENT,NULL);
			}
            
			if (FD_ISSET(fd, &wrSet))
			{
//				printf("can be write fd = %d\n", fd);
				bShouldSleep = false;
				(*handler)(fd,JSWRITEEVENT,NULL);
			}

			if (FD_ISSET(fd, &exSet))
			{
				(*handler)(fd,JSEXCEPTIONEVENT,NULL);
			}

			if (bShouldSleep)
			{
				timespec ts;
				ts.tv_sec = 0;
				ts.tv_nsec = 1000000;
				nanosleep(&ts, 0);
			}
		}
	}

	return 0;
}
